package com.chub.study.modules.controller;

import com.chub.study.modules.entity.TDictInfo;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author : chub
 * @version : V1.0.0
 * @fileName : WebClientController.java
 * @description : 四种方式各有特点，适用于不同的场景：
 *      RestTemplate适用于简单的同步HTTP调用。
 *      WebClient和HttpClient适用于响应式编程和异步处理。
 *      Feign适用于声明式服务调用，简化客户端开发。
 * @createTime : 2023-10-07 16:33
 */
@Api(tags = "Spring 中的两种 web client 实现 - RestTemplate 和 WebClient")
@Slf4j
@RestController
@RequestMapping("/modules/webclient/")
public class WebClientController {

    final static String URL = "http://localhost:7788/modules/tdictinfo/getBydictTypeCodesReturnMap";

    // 在请求时写明请求头的MediaType为application/json格式，可以进行正常调用
    public static HttpHeaders getRequestHeaders() {
        HttpHeaders requestHeaders = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        requestHeaders.setContentType(type);
        requestHeaders.add("Accept", MediaType.APPLICATION_JSON.toString());
        return requestHeaders;
    }


    @PostMapping("/getEntityBlocking")
    public Map<String, List<TDictInfo>> getEntityBlocking() {
        log.info("Starting BLOCKING Controller!");

        Map<String, List<String>> reqMap = new HashMap<>();
        reqMap.put("dictTypeCodes", Stream.of("ADDR_TYPE").collect(Collectors.toList()));
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Map<String, List<String>>> httpEntity = new HttpEntity<>(reqMap, headers);

        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<Map<String, List<TDictInfo>>> resp = restTemplate.exchange(
                URL,
                HttpMethod.POST,
                httpEntity,
                new ParameterizedTypeReference<Map<String, List<TDictInfo>>>() {
                });

        Map<String, List<TDictInfo>> result = resp.getBody();
        log.info(result.toString());
        // result.forEach(entity -> log.info(entity.toString()));
        log.info("Exiting BLOCKING Controller!");
        return result;
    }


    @PostMapping(value = "/getEntityNonBlocking", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<HashMap> getEntityNonBlocking(@RequestBody Map<String, List<String>> reqMap) {
        log.info("Starting NON-BLOCKING Controller!");

        // 不传参数，函数内部指定设置
        // Map<String, List<String>> reqMap = new HashMap<>();
        // reqMap.put("dictTypeCodes", Stream.of("ADDR_TYPE", "MNT_TYPE").collect(Collectors.toList()));

        // Flux<HashMap> respFlux = WebClient.create()
        //         .post()
        //         .uri(URL)
        //         .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        //         .bodyValue(reqMap)   // 添加请求参数
        //         .retrieve()
        //         .bodyToFlux(HashMap.class);// .bodyToFlux();


        WebClient.ResponseSpec responseSpec = WebClient.create()
                .post()
                .uri(URL)
                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .bodyValue(reqMap)   // 添加请求参数
                .retrieve();

        Mono<String> mono = responseSpec
                .onStatus(e -> e.is4xxClientError(), resp ->
                {
                    log.error("error:{},msg:{}", resp.statusCode().value(), resp.statusCode().getReasonPhrase());
                    return Mono.error(new RuntimeException(resp.statusCode().value() + " : " + resp.statusCode().getReasonPhrase()));
                })
                .bodyToMono(String.class)
                .doOnError(WebClientResponseException.class, err ->
                {
                    log.info("ERROR status:{},msg:{}", err.getRawStatusCode(), err.getResponseBodyAsString());
                    throw new RuntimeException(err.getMessage());
                })
                .onErrorReturn("fallback");

        Flux<HashMap> respFlux = responseSpec.bodyToFlux(HashMap.class);


        respFlux.subscribe(entity -> log.info(entity.toString()));
        log.info("Exiting NON-BLOCKING Controller!");
        return respFlux;
    }


}
